package com.gateway.plugin.resilience4j.builder;

import com.gateway.common.dto.RuleData;
import com.gateway.common.dto.convert.rule.Resilience4JHandle;
import com.gateway.common.utils.JsonUtils;
import com.gateway.plugin.base.util.CacheKeyUtils;
import com.gateway.plugin.resilience4j.config.Resilience4JConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.core.IntervalFunction;
import io.github.resilience4j.ratelimiter.RateLimiterConfig;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;

import java.time.Duration;

/**
 * @program: api-gateway
 * @description:
 * @author: YuKai Fan
 * @create: 2025/2/24 10:46
 **/
public final class Resilience4JBuilder {

    private Resilience4JBuilder() {
    }

    public static Resilience4JConfig build(RuleData ruleData) {
        Resilience4JHandle resilience4JHandle = JsonUtils.stringToBean(ruleData.getHandle(), Resilience4JHandle.class);
        resilience4JHandle.checkData(resilience4JHandle);
        TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
                .timeoutDuration(Duration.ofMillis(resilience4JHandle.getTimeoutDuration())).build();
        RateLimiterConfig rateLimiterConfig = null;
        CircuitBreakerConfig circuitBreakerConfig = null;
        if (resilience4JHandle.getCircuitEnable() == 1) {
            circuitBreakerConfig = CircuitBreakerConfig.custom()
                    .recordExceptions(Throwable.class, Exception.class)
                    .failureRateThreshold(resilience4JHandle.getFailureRateThreshold())
                    .automaticTransitionFromOpenToHalfOpenEnabled(resilience4JHandle.getAutomaticTransitionFromOpenToHalfOpenEnabled())
                    .slidingWindow(resilience4JHandle.getSlidingWindowSize(), resilience4JHandle.getMinimumNumberOfCalls(),
                            resilience4JHandle.getSlidingWindowType() == 0
                                    ? CircuitBreakerConfig.SlidingWindowType.COUNT_BASED
                                    : CircuitBreakerConfig.SlidingWindowType.TIME_BASED)
                    .waitIntervalFunctionInOpenState(IntervalFunction.of(Duration.ofMillis(resilience4JHandle.getWaitIntervalFunctionInOpenState())))
                    .permittedNumberOfCallsInHalfOpenState(resilience4JHandle.getPermittedNumberOfCallsInHalfOpenState())
                    .build();
        }
        if (resilience4JHandle.getRateLimitEnable() == 1) {
            rateLimiterConfig = RateLimiterConfig.custom()
                    .limitForPeriod(resilience4JHandle.getLimitForPeriod())
                    .timeoutDuration(Duration.ofMillis(resilience4JHandle.getTimeoutDurationRate()))
                    .limitRefreshPeriod(Duration.ofMillis(resilience4JHandle.getLimitRefreshPeriod()))
                    .build();
        }
        return new Resilience4JConfig(CacheKeyUtils.INST.getKey(ruleData), resilience4JHandle.getFallbackUri(), timeLimiterConfig, circuitBreakerConfig, rateLimiterConfig);
    }
}
